package com.hxy.bean;

import com.hxy.AppConfig;
import io.undertow.util.AttachmentList;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 上下文内容
 */
public class AnnotationConfigApplicationContext {

    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, Object> earlySingletonObjects  = new ConcurrentHashMap<>();
    /**
     * 解析class
     * @param configClass
     */
    public AnnotationConfigApplicationContext(Class configClass) {
        List<Class> classList = scan(configClass);
        for (Class clz : classList) {
            if (clz.isAnnotationPresent(Component.class)) {
                Component component = (Component) clz.getAnnotation(Component.class);
                String beanName = component.value();
                BeanDefinition beanDefinition = new BeanDefinition();
                beanDefinition.setBeanClass(clz);
                beanDefinitionMap.put(beanName, beanDefinition);
            }
        }
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            // 生成对象
            Object bean = createBean(beanName, beanDefinition);
            singletonObjects.put(beanName,bean);
            earlySingletonObjects.remove(beanName);
        }
    }

    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class beanClass = beanDefinition.getBeanClass();
        Object newInstance = null;
        try {
            // 无参构造 生成对象
             newInstance = beanClass.getDeclaredConstructor().newInstance();
             // 提前放入到 earlySingletonObjects 中
             earlySingletonObjects.put(beanName,newInstance);
             Field[] fields = beanClass.getDeclaredFields();
             for (Field field : fields) {
                if(field.isAnnotationPresent(Autowired.class)){
                    //所以依赖注入的,必须是Component过的
                    Object object = getBean(field.getName());
                    field.setAccessible(true);
                    field.set(newInstance,object);
                }
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return newInstance;
    }

    /**
     * 加载路径下面所有的class
     * @param configClass
     * @return
     */
    private List<Class> scan(Class configClass) {
        List<Class> classList = new ArrayList<>();
        ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
        String scanPath  = componentScan.value();
        scanPath = scanPath.replace(".","/");
        ClassLoader classLoader = AnnotationConfigApplicationContext.class.getClassLoader();
        URL resource = classLoader.getResource(scanPath);
        File file = new File(resource.getFile());
        File[] files = file.listFiles();
        for (File f : files) {
            String absolutePath = f.getAbsolutePath();
            // E:\git\saas_common\neetyT\myspring\target\classes\com\hxy\service\AService.class
            //E:\git\saas_common\neetyT\myspring\target\classes\com\hxy\service\Bservice.class

            absolutePath = absolutePath.substring(absolutePath.lastIndexOf("com"), absolutePath.indexOf(".class"));
            absolutePath = absolutePath.replace("\\",".");
           //  System.out.println(absolutePath);
            Class<?> clazz = null;
            try {
                clazz = classLoader.loadClass(absolutePath);
                classList.add(clazz);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }

        }
        return classList;
    }

    public Object getBean(String beanName){
        Object bean = singletonObjects.get(beanName);
        if(bean == null){
            // 如果 singletonObjects没有才从earlySingletonObjects中获取对象
            bean = earlySingletonObjects.get(beanName);
            if(bean == null){
                BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
                bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName,bean);
            }

        }
        return bean;
    }
}
